package org.tang.springcloudvv.config;

import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.tang.springcloudvv.cache.CacheMqQueues;
import org.tang.springcloudvv.model.Log4jjWithBLOBs;
import org.tang.springcloudvv.request.RequestEvent;
import org.tang.springcloudvv.request.RequestThreadLocal;
import org.tang.springcloudvv.util.ExceptionUtil;
import org.tang.springcloudvv.util.IPUtil;
import org.tang.springcloudvv.util.MapUtils;
import org.tang.springcloudvv.util.SessionUtil;
import org.tang.springcloudvv.vo.User;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.util.Date;
import java.util.Map;

/**
 * controller的接口拦截
 */
@Aspect
@Configuration
public class LogRecordAspect {

    private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class);

    // 定义切点Pointcut
    @Pointcut("execution(* com..controller..*Controller.*(..))")
    public void excudeService() {
    }

	@Around("excudeService()")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = sra.getRequest();
		long startTime = System.currentTimeMillis();
		String requestId = UUID.randomUUID().toString().replace("-", "");

		Log4jjWithBLOBs log4jj = new Log4jjWithBLOBs();
		log4jj.setRequestId(requestId);
		try
		{
			log(requestId,request,pjp);
			initLogInfo(startTime,request,log4jj);

			Object result = pjp.proceed();
			dealLog(startTime,request,log4jj);

			return result;
		}
		catch (Exception e)
		{
			log4jj.setOperresult(500);
			log4jj.setError(ExceptionUtil.getExceptionMessage(e,2000));

			throw e;
		}
		finally {

			RequestThreadLocal.clear();

			if (pjp.getTarget() != null)
			{
				CacheMqQueues.add(CacheMqQueues.log4j,log4jj);
			}
		}
	}
	private void log(String requestId,HttpServletRequest request,ProceedingJoinPoint pjp)
	{
		Map<String, String[]> parameterMap = MapUtils.getMapFilter(request.getParameterMap());
		if (parameterMap.size()>0)
		{
			logger.info("请求开始, requestId: {},method: {}, uri: {}, params: {}", requestId,request.getMethod(), request.getRequestURI(),JSONUtil.toJsonStr(parameterMap));
		}
		else
		{
			//@RequestBody参数request.getParameterMap拿不到的情况，通过目标方法的参数获取
			logger.info("请求开始, requestId: {},method: {}, uri: {}", requestId,request.getMethod(), request.getRequestURI());
			logArgs(requestId,pjp.getArgs());
		}
	}
	private void dealLog(long startTime,HttpServletRequest request,Log4jjWithBLOBs log4jj)
	{
		Long useTime = System.currentTimeMillis() - startTime;
		log4jj.setUsedtime(useTime.intValue());
	}

	private void initLogInfo(long startTime,HttpServletRequest request,Log4jjWithBLOBs log4jj)
	{
		log4jj.setUserId(0L);
		//startTime用于打印日志的关键词
		log4jj.setEvent(""+startTime);
		log4jj.setEventPath(request.getRequestURI());

		log4jj.setAccessip(IPUtil.getIpAddr(request));
		log4jj.setCreateTime(new Date());
		log4jj.setOperresult(200);

		User user = SessionUtil.getUser();
		if (user!= null)
		{
			if (user.getUserId() != null)
			{
				log4jj.setUserId(user.getUserId());
			}
			else
			{
				log4jj.setUserId(0L);
			}

			if (user.getUserName() != null)
			{
				log4jj.setUserName(user.getUserName());
			}
		}

		RequestEvent eventPath = new RequestEvent();
		BeanUtils.copyProperties(log4jj,eventPath);
		RequestThreadLocal.setEventPath(eventPath);
	}

	private void logArgs(String requestId,Object[] args)
	{
		if (args != null)
		{
			int i = 0;
			for (Object val:args)
			{
				if (val != null)
				{
					if (val instanceof ServletRequest)
					{
						continue;
					}
					if (val instanceof ServletResponse)
					{
						continue;
					}
					if (val instanceof HttpSession)
					{
						continue;
					}
					if (val instanceof MultipartFile)
					{
						logger.info("请求参数:{}, params: {}", i++,val.getClass().getSimpleName());
						continue;
					}
					if (val instanceof File)
					{
						logger.info("请求参数:{}, params: {}", i++,val.getClass().getSimpleName());
						continue;
					}
				}
				logger.info("请求参数:requestId {}, {}, params: {}", requestId,i++,JSONUtil.toJsonStr(val));
			}
		}
	}


}
